package com.adc.quicktools.file;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.URL;
import java.net.UnknownHostException;
import java.nio.channels.FileChannel;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;


import com.adc.quicktools.StringUtil;


/**
 * 
 * @TypeName: FileControl
 * @Package com.adc.quicktools.file 
 * @Description: TODO( 提供常用的文件操作，复制、删除、读、写、获取换行符、判断是否是linux、获得指定格式的当前时间串等等 ) 
 * @author shen  shenqiao2012@163.com 
 * @date 2012-6-1 下午06:56:26
 */
public class FileControl {
	
	private static final String DefaultCharSet = "UTF-8";
	private static String ChangeLineString;


	/**
	 * @MethodName: writeAsLine
	 * @author  shen
	 * @Description: TODO( 将List<String>中的内容以指定字符集输出到指定文件中，可选择是否追加输出) 
	 * @param path 文件全路径
	 * @param strList 需要输出的string的list
	 * @param isAdd 是否追加文本，不追加即为覆盖；
	 * @param charset 指定的字符集
	 * @return boolean
	 */
	public static boolean writeAsLine(String path, List<String> strList, boolean isAdd, String charset) {
		boolean o=false;
		PrintWriter printwriter=null; 
		if (charset == null || "".equals(charset)) {
			charset = DefaultCharSet;
		}
		try {
			createFile(path);
			printwriter = new PrintWriter(
					new OutputStreamWriter(new FileOutputStream(path, isAdd), charset));
			for (int i = 0; i < strList.size(); i++) {
				// System.out.println("写文件："+fileName+"  内容："+str);
				printwriter.write(strList.get(i) + getChangeLineString());
			}
			printwriter.flush();
			printwriter.close();
			o=true;
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}finally{
			printwriter=null;
		}
		return o;
	}


	/**
	 * @MethodName: writeAsLine
	 * @author  shen
	 * @Description: TODO(将指定的String中的信息按照指定的字符集输出到指定文件中，可选是否追加) 
	 * @param path 指定的文件全路径
	 * @param str 需要输出的String
	 * @param isAdd 是否追加，不追加则覆盖
	 * @param charset 指定的字符集
	 * @return boolean
	 */
	public static boolean writeAsLine(String path, String str, boolean isAdd, String charset) {
		boolean o=false;
		PrintWriter printwriter=null;
		if (charset == null || "".equals(charset)) {
			charset = DefaultCharSet;
		}
		try {
			createFile(path);
			printwriter = new PrintWriter(
					new OutputStreamWriter(new FileOutputStream(path, isAdd), charset));
			// System.out.println("写文件："+fileName+"  内容："+str);
			printwriter.write(str + getChangeLineString());
			printwriter.flush();
			printwriter.close();
			o=true;
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}finally{
			printwriter=null;
		}
		return o;
	}
	
	/**
	 * 
	 * Description:  根据传入的io stream 处理内容；即从inputStream中读入信息，并按照byte[1024] 写入outputStream 
	 * author:  shen
	 * @param inputStream  输入流
	 * @param outputStream  输出流
	 * @return boolean 写入成功，返回true，反之则返回false；
	 */
	public static boolean writeOrReadAsStream(InputStream inputStream,OutputStream outputStream) {
		boolean b=false;
		InputStream in = null;  
        OutputStream out = null;
        try {
			in = new BufferedInputStream(inputStream);  
			out = new BufferedOutputStream(outputStream);  
			int byteread = 0; // 读取的字节数
			byte []buffer = new byte[1024];  
			while((byteread=in.read(buffer)) != -1){  
			    out.write(buffer,0,byteread);  
			    buffer = new byte[1024];  
			}
			out.flush();
			b=true;
		} catch (IOException e) {
			e.printStackTrace();
		}  finally{
			try {  
                out.close();  
                in.close();  
            } catch (IOException e) {  
                e.printStackTrace();  
            }  
		}
        return b;
	}


	/**
	 * @MethodName: readFileByLines
	 * @author  shen
	 * @Description: TODO( 以指定字符集按行读取指定文件  ) 
	 * @param fileName  指定的文件名
	 * @param charset  指定的字符集
	 * @return List<String> 返回的读取内容，每行是一个String
	 */
	public static List<String> readFileByLines(String fileName, String charset) {
		if (charset == null || "".equals(charset)) {
			charset = DefaultCharSet;
		}
		List<String> fileList = new ArrayList<String>();
		File file = new File(fileName);
		BufferedReader reader = null;
		try {
			// System.out.println("以行为单位读取文件内容，一次读一整行：");
			reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), charset));
			String tempString = null;
			while ((tempString = reader.readLine()) != null) {
				fileList.add(tempString);
			}
			reader.close();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (reader != null) {
				try {
					reader.close();
				} catch (IOException e1) {
					System.out.println("reader 关闭时出现异常！");
				}
			}
		}
		return fileList;
	}

	
	/**
	 * @MethodName: getChangeLineString
	 * @author  shen
	 * @Description: TODO( 获取换行符，根据linux和windows获取不同的换行符 )  
	 * @return String
	 */
	public static String getChangeLineString() {
		if (isLinux()) {
			ChangeLineString = "\n";
		} else {
			ChangeLineString = "\r\n";
		}
		return ChangeLineString;
	}

	
	/**
	 * @MethodName: gainLocalIP
	 * @author  shen
	 * @Description: TODO( 获取本机ip )  
	 * @return String
	 */
	public static String gainLocalIP() {
		String ip=null;
		InetAddress inet = null;
		try {
			inet = InetAddress.getLocalHost();
			ip=inet.getHostAddress();
		} catch (UnknownHostException e) {
			e.printStackTrace();
		}finally{
			inet=null;
		}
		return ip;
	}


	/**
	 * @MethodName: isLinux
	 * @author  shen
	 * @Description: TODO( 判断系统是否是linux，是则返回true，不是则返回否 )  
	 * @return boolean
	 */
	public static boolean isLinux() {
		boolean isLinux = false;
		URL resource = FileControl.class.getResource("FileControl.class");
		String classPath = resource.getPath();
		String className = FileControl.class.getName().replace('.', '/') + ".class";
		String classesPath = classPath.substring(0, classPath.indexOf(className));
		if ((System.getProperty("os.name").toUpperCase().indexOf("WINDOWS") != -1) && (classesPath.startsWith("/"))) {
			classesPath = classesPath.substring(1);
			// System.out.println(classesPath);
			isLinux = false;
		} else {
			isLinux = true;
		}
		return isLinux;
	}

	
	/**
	 * @MethodName: fileScanner
	 * @author  shen
	 * Description: 遍历搜索目标文件夹，检查目标文件是否存在,如果文件存在,返回文件绝对路径，否则返回空 ;查找第一个匹配的文件；
	 * @param _parent 搜索的路径
	 * @param _needfilename 需要的参数文件的文件名 
	 * @return String
	 */
	public static String fileScanner(String _parent, String _needfilename) {
		String result="";
		File tempDir = new File(_parent);
		String flag = "";
		File[] filename = tempDir.listFiles();
		for (int i = 0; i < filename.length; i++) {
			if (filename[i].isFile()) {
//				System.out.println(filename[i]);
				if (filename[i].getName().equals(_needfilename)) {
//					System.err.println(">>>>>>"+filename[i].getAbsolutePath());
					result=filename[i].getAbsolutePath();
					break;
				}
			}else if (filename[i].isDirectory()) {
//				System.err.println(filename[i]);
				flag=fileScanner(filename[i].getAbsolutePath(), _needfilename);
				if (StringUtil.checkStringValue(flag)) {
					result=flag;
				}
			}
		}
		return result;
	}


	/**
	 * @MethodName: copyFile
	 * @author  shen
	 * @Description: TODO( 文件拷贝。是通过NIO管道对管道复制； ) 
	 * @param from 源路径+文件名。
	 * @param to 目标路径+文件名。
	 * @return long  如果返回-1L，则表示拷贝失败，返回大于0的值，即返回文件拷贝的时间，单位是毫秒
	 */
	public static long copyFile(String from, String to) {
		File file1, file2;
		file1 = new File(from);
		ensurePathExist(to);  //  确保输出文件的父路径存在
		file2 = new File(to);
		long result=-1L;
		long ms = new Date().getTime();
		int length = 2097152;
		try {
			FileInputStream in = new FileInputStream(file1);
			FileOutputStream out = new FileOutputStream(file2);
			FileChannel inC = in.getChannel();
			FileChannel outC = out.getChannel();
			while (true) {
				if (inC.position() == inC.size()) {
					inC.close();
					outC.close();
					result=new Date().getTime() - ms;
					break;
				}
				if ((inC.size() - inC.position()) < 20971520) {
					length = (int) (inC.size() - inC.position());
				} else {
					length = 20971520;
				}
				inC.transferTo(inC.position(), length, outC);
				inC.position(inC.position() + length);
			}
		} catch (FileNotFoundException e) {
			System.out.println("文件拷贝失败：["+from+"] to ["+to+"]! 未找到文件！");
			e.printStackTrace();
		} catch (IOException e) {
			System.out.println("文件拷贝失败：["+from+"] to ["+to+"]!  IO错误！");
			e.printStackTrace();
		}
		return result;
	}

	
	/**
	 * @MethodName: copyFile
	 * @author  shen
	 * @Description: TODO( 复制单个文件 ) 
	 * @param srcFileName 待复制的文件全路径
	 * @param destFileName 目标文件全路径
	 * @param overlay 如果目标文件存在，是否覆盖 
	 * @return boolean 如果复制成功返回true，否则返回false
	 */
	public static boolean copyFile(String srcFileName, String destFileName, boolean overlay) {
		File srcFile = new File(srcFileName);
		// 判断源文件是否存在
		if (!srcFile.exists()) {
			System.out.println("源文件：" + srcFileName + "不存在！");
			return false;
		} else if (!srcFile.isFile()) {
			System.out.println("复制文件失败，源文件：" + srcFileName + "不是一个文件！");
			return false;
		}

		// 判断目标文件是否存在
		File destFile = new File(destFileName);
		if (destFile.exists()) {
			// 如果目标文件存在并允许覆盖
			if (overlay)
				// 删除已经存在的目标文件，无论目标文件是目录还是单个文件
				new File(destFileName).delete();
		} else {
			// 如果目标文件所在目录不存在，则创建目录
			if (!destFile.getParentFile().exists()) {
				// 目标文件所在目录不存在
				if (!destFile.getParentFile().mkdirs()) {
					// 复制文件失败：创建目标文件所在目录失败
					return false;
				}
			}
		}

		// 复制文件
		int byteread = 0; // 读取的字节数
		InputStream in = null;
		OutputStream out = null;
		try {
			in = new FileInputStream(srcFile);
			out = new FileOutputStream(destFile);
			byte[] buffer = new byte[1024];
			while ((byteread = in.read(buffer)) != -1) {
				out.write(buffer, 0, byteread);
			}
			return true;
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			return false;
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		} finally {
			try {
				if (out != null)
					out.close();
				if (in != null)
					in.close();
			} catch (IOException e) {
				System.out.println("I/O关闭时出现异常！");
			}
		}
	}

	/**
	 * @MethodName: copyDirectory
	 * @author  shen
	 * @Description: TODO( 复制整个目录的内容 ) 
	 * @param srcDirName 待复制目录的目录名
	 * @param destDirName 目标目录名
	 * @param overlay  如果目标目录存在，是否覆盖
	 * @return boolean 如果复制成功返回true，否则返回false
	 */
	public static boolean copyDirectory(String srcDirName, String destDirName, boolean overlay) {
		// 判断源目录是否存在
		File srcDir = new File(srcDirName);
		if (!srcDir.exists()) {
			System.out.println( "复制目录失败：源目录" + srcDirName + "不存在！");
			return false;
		} else if (!srcDir.isDirectory()) {
			System.out.println( "复制目录失败：" + srcDirName + "不是目录！");
			return false;
		}

		// 如果目标目录名不是以文件分隔符结尾，则加上文件分隔符
		destDirName=checkDirEndWith(destDirName);
		File destDir = new File(destDirName);
		// 如果目标文件夹存在
		if (destDir.exists()) {
			// 如果允许覆盖则删除已存在的目标目录
			if (overlay) {
				new File(destDirName).delete();
			} else {
				System.out.println( "复制目录失败：目的目录" + destDirName + "已存在！" ); 
				return false;
			}
		} else {
			createFolder(destDirName);  // 创建目的目录
		}

		boolean flag = true;
		File[] files = srcDir.listFiles();
		for (int i = 0; i < files.length; i++) {
			// 复制文件
			if (files[i].isFile()) {
				flag = copyFile(files[i].getAbsolutePath(),
							destDirName + files[i].getName(), overlay);
				if (!flag)
					break;
			} else if (files[i].isDirectory()) {
				flag = copyDirectory(files[i].getAbsolutePath(),
							destDirName + files[i].getName(), overlay);
				if (!flag)
					break;
			}
		}
		if (!flag) {
			System.out.println( "复制目录" + srcDirName + "至" + destDirName + "失败！"); 
			return false;
		} else {
			System.out.println( "复制目录" + srcDirName + "至" + destDirName + "成功！");
			return true;
		}
	}

	/**
	 * @MethodName: createFolder
	 * @author  shen
	 * @Description: TODO( 创建目录 ) 
	 * @param _dir 需要创建的目录
	 * @return boolean 
	 */
	public static boolean createFolder(String _dir) {
		boolean o=false;
		File dir = new File(_dir);
		if (dir.exists()) {
			System.out.println( "创建目录" + _dir + "失败，目标目录已存在！");
		} else {
			// 创建单个目录
			ensurePathExist(_dir);   //   保证父级目录全部存在
			if (dir.mkdirs()) {
				System.out.println( "创建目录" + _dir + "成功！");
				o=true;
			} else {
				System.out.println( "创建目录" + _dir + "失败！");
			}
		}
		return o;
	}

	/**
	 * @MethodName: createFile
	 * @author  shen
	 * @Description: TODO( 根据指定路径创建单个文件 ) 
	 * @param filepath 指定的文件全路径
	 * @return void
	 */
	public static boolean createFile(String filepath) {
		boolean o=false;
		try {
			ensurePathExist(filepath);
			if (new File(filepath).createNewFile()) {
				System.out.println( "文件[" + filepath + "]创建成功！");
				o=true;
			} else {
				System.out.println(  "文件[" + filepath + "]创建失败！");
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return o;
	}

	/**
	 * @MethodName: createFile
	 * @author  shen
	 * @Description: TODO( 根据指定目录、指定文件名及后缀创建单个文件 ) 
	 * @param _dir  指定的目录
	 * @param _name  指定的不带后缀的文件名
	 * @param _suffix  后缀
	 * @return boolean  返回是否创建成功
	 */
	public static boolean createFile(String _dir, String _name, String _suffix) {
		boolean o=false;
		_dir = checkDirEndWith(_dir);
		if (_name!=null) {
			_dir = _dir + _name;
			if ( _suffix!=null) {
				_dir=_dir+"." + _suffix;
			}
		} 
		try {
			ensurePathExist(_dir);
			if (new File(_dir).createNewFile()) {
				o=true;
				System.out.println("文件[" + _dir + "]创建成功！");
			} else {
				System.out.println( "文件[" + _dir + "]创建失败！");
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return o;
	}

	/**
	 * @MethodName: deleteTempFolder
	 * @author  shen
	 * @Description: TODO( 删除指定的临时文件夹下的所有东西 ) 
	 * @param _tempdir 需要删除的临时目录
	 * @return boolean
	 */
	public static boolean deleteTempFolder(String _tempdir) {
		boolean o=false;
		File tempDir = new File(_tempdir);
		File[] filename = tempDir.listFiles();
		while (!tempDir.delete()) {
			for (int i = 0; i < filename.length; i++) {
				filename[i].delete();
			}
		}
		if (!tempDir.exists()) {
			o=true;
		}
		return o;
	}

	/**
	 * @MethodName: deleteTempFile
	 * @author  shen
	 * @Description: TODO( 删除临时文件 ) 
	 * @param filePath 指定的文件全路径
	 * @return boolean
	 */
	public static boolean deleteTempFile(String filePath) {
		boolean o=false;
		File tempFile = new File(filePath);
		if (tempFile.exists()) {
			if (tempFile.delete()) {
				o=true;
				System.out.println("File ["+filePath+"] is delete!");
			}else {
				System.out.println( "[WARNING:]File ["+filePath+"] delete Error!" );
			}
		}
		return o;
	}

	/**
	 * @MethodName: ensurePathExist
	 * author  shen
	 * Description:保证指定路径的的父目录全部存在 ,如果存在，则返回true；反之返回false；
	 * @param filepath 指定的路径 
	 * @return boolean
	 */
	public static boolean ensurePathExist(String filepath) {
		boolean o=false;
		File file = new File(filepath);
		if (!file.exists()) {
			String dir = file.getParent();
			File fileParent = new File(dir);
			if (fileParent.mkdirs()) {
				o=true;
			}else {
				System.out.println("["+dir+"] 已存在！");
			}
		}
		if (new File(new File(filepath).getParent()).exists()) {
			o=true;
		}
		return o;
	}

	/**
	 * @Title: getCurrentTimeString
	 * @Description: TODO( 按格式获取当前时间对应的字符串
	 * @param formatString
	 *            “yyyyMMddHHmmss”等时间格式串
	 * @Return String
	 */
	public static String getCurrentTimeString(String formatString) {
		if (formatString == null || "".equals(formatString)) {
			return new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
		} else {
			return new SimpleDateFormat(formatString).format(new Date());
		}
	}
	
	/**
	 * @MethodName: checkDirEndWith
	 * @author  shen
	 * @Description: TODO( 检查目录的最后一位是否是文件路径分隔符 ) 
	 * @param filedir  指定某一文件路径
	 * @return String 返回带有文件路径分隔符的路径
	 */
    public static String checkDirEndWith(String filedir) {
    	String str=File.separator;
		if (!filedir.endsWith("\\")&&!filedir.endsWith("/")) {
			filedir=filedir+str;
		}
		System.out.println("路径为：["+filedir+"]");
		return filedir;
	}
    
	 /**
	 * @MethodName: checkDirEndWith
	 * @author  shen
	 * @Description: TODO( getAppPath需要一个当前程序使用的Java类的class属性参数，
	 * 它可以返回打包过的Java可执行文件（jar，war）所处的系统目录名或
	 * 非打包Java程序所处的目录 ) 
     *@param cls为Class类型
     *@return 返回值为该类所在的Java程序运行的目录 
     */
	@SuppressWarnings("rawtypes")
	public static String getAppPath(Class cls){
        //检查用户传入的参数是否为空
        if(cls==null) 
         throw new java.lang.IllegalArgumentException("参数不能为空！");
        ClassLoader loader=cls.getClassLoader();
        //获得类的全名，包括包名
        String clsName=cls.getName()+".class";
        //获得传入参数所在的包
        Package pack=cls.getPackage();
        String path="";
        //如果不是匿名包，将包名转化为路径
        if(pack!=null){
            String packName=pack.getName();
           //此处简单判定是否是Java基础类库，防止用户传入JDK内置的类库
           if(packName.startsWith("java.")||packName.startsWith("javax.")) 
              throw new java.lang.IllegalArgumentException("不要传送系统类！");
            //在类的名称中，去掉包名的部分，获得类的文件名
            clsName=clsName.substring(packName.length()+1);
            //判定包名是否是简单包名，如果是，则直接将包名转换为路径，
            if(packName.indexOf(".")<0) path=packName+"/";
            else{//否则按照包名的组成部分，将包名转换为路径
                int start=0,end=0;
                end=packName.indexOf(".");
                while(end!=-1){
                    path=path+packName.substring(start,end)+"/";
                    start=end+1;
                    end=packName.indexOf(".",start);
                }
                path=path+packName.substring(start)+"/";
            }
        }
        //调用ClassLoader的getResource方法，传入包含路径信息的类文件名
        java.net.URL url =loader.getResource(path+clsName);
        //从URL对象中获取路径信息
        String realPath=url.getPath();
        //去掉路径信息中的协议名"file:"
        int pos=realPath.indexOf("file:");
        if(pos>-1) realPath=realPath.substring(pos+5);
        //去掉路径信息最后包含类文件信息的部分，得到类所在的路径
        pos=realPath.indexOf(path+clsName);
        realPath=realPath.substring(0,pos-1);
        //如果类文件被打包到JAR等文件中时，去掉对应的JAR等打包文件名
        if(realPath.endsWith("!"))
            realPath=realPath.substring(0,realPath.lastIndexOf("/"));
      /*------------------------------------------------------------
       ClassLoader的getResource方法使用了utf-8对路径信息进行了编码，当路径
        中存在中文和空格时，他会对这些字符进行转换，这样，得到的往往不是我们想要
        的真实路径，在此，调用了URLDecoder的decode方法进行解码，以便得到原始的
        中文及空格路径
      -------------------------------------------------------------*/

        try {
			realPath=java.net.URLDecoder.decode(realPath,"utf-8");
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			System.out.println(" 路径转换出错，存在不支持的字符！ ");
			e.printStackTrace();
		}
       return realPath;
    }//getAppPath定义结束
    

//	public static void main(String[] args) {
//		String filepath = "E:/TempTest/tttttt/222222/11111113/456774/123578/";
//		// ToolsUtil.ensurePathExist(filepath);
//		File file=new File(filepath);
//		if(file.mkdir()){
//			System.err.println("mkdir  success;");
//		}
//		if(file.mkdirs()){
//			System.err.println("mkdirs  success;");
//		}
//		
//	}

}
